#include "creature.hpp"
#include "nature.hpp"

int Creature::g_index = 0;

void Creature::move_to(const Position &p)
{
    Nature *g_nature = Nature::get_instance();

    g_nature->move_to(this, p);
    std::cout << m_id << " move to (" << p.x << ", " << p.y << ")" << std::endl;

    this->m_position = p;
}

Event *Creature::foraging(const Position &p)
{
    Nature *g_nature = Nature::get_instance();

    if (!g_nature->has_position(p))
    {
        return nullptr;
    }

    auto sets = g_nature->get_creature(p);

    if (nullptr == sets)
        return nullptr;

    for (auto c : *sets)
    {
        if (this->can_eat(c))
        {
            Event *e = new Event(NET_EAT, Nature::get_instance()->get_round());
            e->set_id(this->m_id);
            e->set_target_id(c->id());
            e->set_old_pos(this->m_position);
            e->set_new_pos(c->position());

            this->move_to(p);
            this->eat(c);

            return e;
        }
    }
    return nullptr;
}

Event *Creature::foraging()
{
    std::cout << m_id << " foraging" << std::endl;

    Event *e = nullptr;
    do
    {

        e = this->foraging(this->m_position);
        // 相同位置觅食
        if (e)
            break;

        // TODO 活动范围实际是个十字形，只能直线移动...
        for (int i = 1; i <= this->m_sight; ++i)
        {
            Position p1 = this->m_position;
            p1.x += i;

            e = this->foraging(p1);
            if (e)
                break;

            Position p2 = this->m_position;
            p2.x -= i;

            e = this->foraging(p2);
            if (e)
                break;

            Position p3 = this->m_position;
            p3.y += i;

            e = this->foraging(p3);
            if (e)
                break;

            Position p4 = this->m_position;
            p4.y -= i;

            e = this->foraging(p4);
            if (e)
                break;
        }
    } while (0);

    return e;
}

Event *Creature::survive()
{
    // TODO 同觅食，在视野范围搜索天敌，然后躲避； TODO 躲避算法
    std::cout << m_id << " survive" << std::endl;
    return nullptr;
}

Event *Creature::stroll()
{
    std::cout << m_id << " stroll" << std::endl;

    // 粗暴的随机移动
    Position p = this->m_position;
    p.x += (int)random() % (2 * m_sight) - (m_sight - 1);
    p.y += (int)random() % (2 * m_sight) - (m_sight - 1);

    Nature *g_nature = Nature::get_instance();

    if (g_nature->has_position(p))
    {
        Event *e = new Event(NET_STROLL, Nature::get_instance()->get_round());
        e->set_id(this->m_id);
        e->set_old_pos(this->m_position);
        e->set_new_pos(p);

        this->move_to(p);

        return e;
    }
    return nullptr;
}

void Creature::die()
{
    std::cout << m_id << " die" << std::endl;

    Nature *g_nature = Nature::get_instance();
    g_nature->remove_creature(this);
}

void Creature::eat(Creature *c)
{
    Nature *g_nature = Nature::get_instance();

    std::cout << m_id << " eat " << c->m_id << std::endl;

    this->m_hunger -= 50;
    if (this->m_hunger < 0)
        this->m_hunger = 0;

    g_nature->remove_creature(c);
}

void Creature::to_string(std::string &str)
{
    str.clear();

    str.append((const char *)&m_id, sizeof(m_id));
    str.append((const char *)&m_type, sizeof(m_type));
    str.append((const char *)&(m_position.x), sizeof(m_position.x));
    str.append((const char *)&(m_position.y), sizeof(m_position.y));
    str.append((const char *)&m_age, sizeof(m_age));
    str.append((const char *)&m_hp, sizeof(m_hp));
    str.append((const char *)&m_hunger, sizeof(m_hunger));
    str.append((const char *)&m_sight, sizeof(m_sight));
    str.append((const char *)&m_gender, sizeof(m_gender));
}

bool Creature::from_string(const std::string &str)
{
    // TODO ugly，没有错误校验
    size_t offset = 0;

    m_id = *((int *)(str.data() + offset));
    offset += sizeof(m_id);

    m_type = *((CreatureType *)(str.data() + offset));
    offset += sizeof(m_type);

    m_position.x = *((int *)(str.data() + offset));
    offset += sizeof(int);

    m_position.y = *((int *)(str.data() + offset));
    offset += sizeof(int);

    m_age = *((int *)(str.data() + offset));
    offset += sizeof(int);

    m_hp = *((int *)(str.data() + offset));
    offset += sizeof(int);

    m_hunger = *((int *)(str.data() + offset));
    offset += sizeof(int);

    m_sight = *((int *)(str.data() + offset));
    offset += sizeof(int);

    m_gender = *((bool *)(str.data() + offset));
    offset += sizeof(bool);

    return true;
}